package models;
/**
*
* The functions class defines all the possibles functions on a polynomial: add,
* sub, mul, div, differentiate, integrate, find root, evaluate
*
*/
public class Functions {
public static double ERROR = 0.00001, MAXRANGE = 1_000_000;
/**
* the add function adds two polynomial
*
* @param p1
* -- the first polynomial
* @param p2
* -- the second polynomial
* @return -- the resulting polinomial.
*
* Since the add function is not used in functions handling
* polynomial with real coefficients (divide and integrate) it is
* only defined for polynomials with integer coefficients
*/
public static Polynomial add(Polynomial p1, Polynomial p2) {
Polynomial p;
int degree;
if (p1.getDegree() < p2.getDegree()) {
degree = p2.getDegree();
} else {
degree = p1.getDegree();
}
Coefficient[] coefficients = new Coefficient[degree + 1];
int i;
for (i = 0; i <= degree; i++) {
if (i > p1.getDegree()) {
coefficients[degree - i] = new CoefficientInt(
((CoefficientInt) p2.getCoefficients()[degree - i]).getCoefficient());
} else if (i > p2.getDegree()) {
coefficients[degree - i] = new CoefficientInt(
((CoefficientInt) p1.getCoefficients()[degree - i]).getCoefficient());
} else {
coefficients[degree - i] = new CoefficientInt(
((CoefficientInt) p1.getCoefficients()[p1.getDegree() - i]).getCoefficient()
+ ((CoefficientInt) p2.getCoefficients()[p2.getDegree() - i]).getCoefficient());
}
}
p = new Polynomial(StringToPolynomial.eraseLeadingZeros(coefficients, degree));
return p;
}
/**
* the function subtracts two polynomial
*
* @param p1
* -- first polynomial
* @param p2
* -- second polynomial
* @return -- returns the resulting polynomial.
*
* Since the subtract function is used in functions handling
* polynomial with real coefficients (divide) it is defined for
* polynomials with both integer and real coefficients
*/
public static Polynomial subtract(Polynomial p1, Polynomial p2) {
Polynomial p;
int degree;
if (p1.getDegree() < p2.getDegree()) {
degree = p2.getDegree();
} else {
degree = p1.getDegree();
}
Coefficient[] coefficients = new Coefficient[degree + 1];
int i;
if (p1.getCoefficients()[0].getType() == CoefficientType.INT) {
for (i = 0; i <= degree; i++) {
if (i > p1.getDegree()) {
coefficients[degree - i] = new CoefficientInt(
-((CoefficientInt) p2.getCoefficients()[degree - i]).getCoefficient());
} else if (i > p2.getDegree()) {
coefficients[degree - i] = new CoefficientInt(
((CoefficientInt) p1.getCoefficients()[degree - i]).getCoefficient());
} else {
coefficients[degree - i] = new CoefficientInt(
((CoefficientInt) p1.getCoefficients()[p1.getDegree() - i]).getCoefficient()
- ((CoefficientInt) p2.getCoefficients()[p2.getDegree() - i]).getCoefficient());
}
}
} else {
for (i = 0; i <= degree; i++) {
if (i > p1.getDegree()) {
coefficients[degree - i] = new CoefficientReal(
-((CoefficientReal) p2.getCoefficients()[degree - i]).getCoefficient());
} else if (i > p2.getDegree()) {
coefficients[degree - i] = new CoefficientReal(
((CoefficientReal) p1.getCoefficients()[degree - i]).getCoefficient());
} else {
coefficients[degree - i] = new CoefficientReal(
((CoefficientReal) p1.getCoefficients()[p1.getDegree() - i]).getCoefficient()
- ((CoefficientReal) p2.getCoefficients()[p2.getDegree() - i]).getCoefficient());
}
}
}
p = new Polynomial(StringToPolynomial.eraseLeadingZeros(coefficients, degree));
return p;
}
/**
* the function multiplies two polynomial
*
* @param p1
* -- first polynomial
* @param p2
* -- second polynomial
* @return -- returns the resulting polynomial.
*
* Since the multiply function is used in functions handling
* polynomial with real coefficients (divide) it is defined for
* polynomials with both integer and real coefficients
*/
public static Polynomial multiply(Polynomial p1, Polynomial p2) {
Polynomial p;
int i, j, degree = p1.getDegree() + p2.getDegree();
Coefficient[] coefficients = new Coefficient[degree + 1];
if (p1.getCoefficients()[0].getType() == CoefficientType.INT) {
for (i = 0; i <= degree; i++) {
coefficients[i] = new CoefficientInt(0);
for (j = i; j >= 0; j--) {
if (j <= p1.getDegree() && (i - j) <= p2.getDegree()) {
((CoefficientInt) coefficients[i])
.setCoefficient(((CoefficientInt) coefficients[i]).getCoefficient()
+ ((CoefficientInt) p1.getCoefficients()[j]).getCoefficient()
* ((CoefficientInt) p2.getCoefficients()[i - j]).getCoefficient());
}
}
}
} else {
for (i = 0; i <= degree; i++) {
coefficients[i] = new CoefficientReal(0);
for (j = i; j >= 0; j--) {
if (j <= p1.getDegree() && (i - j) <= p2.getDegree()) {
((CoefficientReal) coefficients[i])
.setCoefficient(((CoefficientReal) coefficients[i]).getCoefficient()
+ ((CoefficientReal) p1.getCoefficients()[j]).getCoefficient()
* ((CoefficientReal) p2.getCoefficients()[i - j]).getCoefficient());
}
}
}
}
p = new Polynomial(StringToPolynomial.eraseLeadingZeros(coefficients, degree));
return p;
}
/**
* the function divides two polynomial
*
* @param p1
* -- first polynomial
* @param p2
* -- second polynomial
* @return -- returns the resulting polynomial.
*
* the divide function is used only for polynomials with real
* coefficients
*/
public static Polynomial[] divide(Polynomial p1, Polynomial p2) throws ArithmeticException {
if (p2.getDegree() == 0 && ((CoefficientReal) p2.getCoefficients()[0]).getCoefficient() == 0) {
throw new ArithmeticException("Cannot divide by zero");
}
int quotientDegree = p1.getDegree() - p2.getDegree();
Coefficient[] coefficientsQuotient;
Polynomial quotient;
Polynomial rest;
Polynomial copyOfP1 = p1;
Polynomial[] p = new Polynomial[2];
if (p1.getDegree() < p2.getDegree()) {
coefficientsQuotient = new CoefficientReal[] { new CoefficientReal(0) };
} else {
coefficientsQuotient = new CoefficientReal[quotientDegree + 1];
int i;
for (i = 0; i <= quotientDegree; i++) {
coefficientsQuotient[i] = new CoefficientReal(0);
}
for (i = 0; copyOfP1.getDegree() >= p2.getDegree(); i++) {
((CoefficientReal) coefficientsQuotient[i])
.setCoefficient(((CoefficientReal) copyOfP1.getCoefficients()[0]).getCoefficient()
/ ((CoefficientReal) p2.getCoefficients()[0]).getCoefficient());
copyOfP1 = subtract(p1, multiply(p2,
new Polynomial(StringToPolynomial.eraseLeadingZeros(coefficientsQuotient, quotientDegree))));
if (copyOfP1.getDegree() == 0) {
break;
}
}
}
quotient = new Polynomial(StringToPolynomial.eraseLeadingZeros(coefficientsQuotient, quotientDegree));
rest = subtract(p1, multiply(p2, quotient));
p[0] = quotient;
p[1] = rest;
return p;
}
/**
* this evaluates a polynomial at a given point
*
* @param p
* -- polynomial to be evaluated
* @param n
* -- point to be evaluated
* @return -- p(n)
*/
public static double evaluateAt(Polynomial p, double n) {
int i;
double pOfN = 0;
for (i = 0; i <= p.getDegree(); i++) {
pOfN = pOfN + ((CoefficientInt) p.getCoefficients()[i]).getCoefficient() * (Math.pow(n, p.getDegree() - i));
}
return pOfN;
}
/**
* this function finds the closest root of polynomial p to a point using the
* bisection method
*
* @param p
* @param point
* @return -- the closest root to point of polynomial p
* @throws HasNoRealRootException
*/
public static double rootArroundPoint(Polynomial p, double point) throws HasNoRealRootException {
double a = point - 1, b = point + 1, c, pAtA, pAtB, pAtC;
pAtA = evaluateAt(p, a);
pAtB = evaluateAt(p, b);
while (pAtA * pAtB > 0 && a > point - MAXRANGE && b < point + MAXRANGE) {
a--;
b++;
pAtA = evaluateAt(p, a);
pAtB = evaluateAt(p, b);
}
if (pAtA == 0)
return a;
if (pAtB == 0)
return b;
if (a <= point - MAXRANGE || b >= point + MAXRANGE) {
throw new HasNoRealRootException("Has no real root arround point " + point);
}
c = 0.5 * (a + b);
pAtC = evaluateAt(p, c);
while (pAtC != 0 && Math.abs(c - a) > ERROR) {
if (pAtC * pAtA > 0) {
a = c;
} else {
b = c;
}
c = 0.5 * (a + b);
pAtC = evaluateAt(p, c);
pAtA = evaluateAt(p, a);
}
return c;
}
/**
* this function calculates the derivative of a polynomial p
*
* @param p
* -- polynomial to be differentiated
* @return -- p'
*
* Since differentiate is not used in functions handling polynomials
* with real coefficients (integrate, divide) it is only defined for
* polynomials with integer coefficients
*/
public static Polynomial differentiate(Polynomial p) {
Polynomial derivative;
Coefficient[] coefficientsOfDerivative;
if (p.getDegree() == 0) {
coefficientsOfDerivative = new Coefficient[] { new CoefficientInt(0) };
} else {
coefficientsOfDerivative = new Coefficient[p.getDegree()];
int i;
for (i = 0; i < p.getDegree(); i++) {
coefficientsOfDerivative[i] = new CoefficientInt(
((CoefficientInt) p.getCoefficients()[i]).getCoefficient() * (p.getDegree() - i));
}
}
derivative = new Polynomial(coefficientsOfDerivative);
return derivative;
}
/**
* this function integrates a polynomial
*
* @param p
* -- Polynomial to be integrated
* @return -- integrated polynomial
*
* this function is only defined for polynomials with real
* coefficients
*/
public static Polynomial integrate(Polynomial p) {
Polynomial antiderivative;
Coefficient[] coefficientOfAntiDerivative = new CoefficientReal[p.getDegree() + 2];
int i;
for (i = 0; i < p.getDegree() + 1; i++) {
coefficientOfAntiDerivative[i] = new CoefficientReal(
((CoefficientReal) p.getCoefficients()[i]).getCoefficient() / (p.getDegree() + 1 - i));
}
coefficientOfAntiDerivative[i] = new CoefficientReal(0);
antiderivative = new Polynomial(
StringToPolynomial.eraseLeadingZeros(coefficientOfAntiDerivative, p.getDegree() + 1));
return antiderivative;
}
}